#include "sdlengine.hpp"
using namespace sdl_engine;

class TestAudio: public App {
public:
    struct SoundBlock {
        AudioSample* sample = nullptr;
        int curPos = 0;

        inline void Reset() {
            curPos = 0;
        }

        inline bool Valid() const { return sample; }

        inline bool IsComplete() const {
            return Valid() ? curPos >= sample->GetSize() : false;
        }

        void Reset(AudioSample* s) {
            sample = s;
            Reset();
        }
    };

    void Init() override {
        auto num = GetPlaybackAudioDeviceNum();
        if (num)
            Logi(Fmt("has %d playback audio device", num));
        num = GetRecordDeviceDeviceNum();
        if (num)
            Logi(Fmt("has %d record audio device", num));

        sample_.reset(new AudioSample("assets/pickup.wav"));

        auto& config = sample_->GetConfig();
        soundBlock_.sample = sample_.get();
        config.SetCallback([](void* userdata, u8* stream, int len) {
                                SoundBlock* block = (SoundBlock*)userdata;
                                if (block->Valid() && !block->IsComplete()) {
                                    SDL_memset(stream, 0, len);
                                    auto& sample = block->sample;
                                    int64_t remaning = block->sample->GetSize() - block->curPos;
                                    if (remaning > len) {
                                        MixAudio(stream, sample->GetData() + block->curPos, len, SDL_MIX_MAXVOLUME);
                                        block->curPos += len;
                                    } else {
                                        MixAudio(stream, sample->GetData() + block->curPos, remaning, SDL_MIX_MAXVOLUME);
                                        block->curPos += remaning;
                                    }
                                }
                            });
        config.SetUserdata(&soundBlock_);

        device_.reset(new AudioDevice(config, true));

        device_->Start();
    }

    void Render(Renderer&) override {
        auto& innerFont = engine.GetInnerBmpFont();
        innerFont.Render("PRESS SPACE TO PLAY AUDIO", 16, point(0, 0), Color::White);
    }

    void OnKeyDown(const EventKeyDown& event) override {
        if (event.Key() == SDLK_SPACE) {
            soundBlock_.Reset(sample_.get());
        }
    }

private:
    Unique<AudioDevice> device_;
    Unique<AudioSample> sample_;
    SoundBlock soundBlock_;
};

int main(int argc, char** argv) {
    Window::CreateInfo createInfo;
    createInfo.SetSize(size(420, 360));

    engine.Init(argc, argv, createInfo, Renderer::CreateInfo(), false);

    TestAudio test;
    engine.SetApp(&test);

    RUN_ENGINE();

    engine.Shutdown();
    return 0;
}
